#include "StdAfx.h"

#include "resource.h"

#include <fstream>
#include <cmath>
#include "waconsts.h"
#include "waitbox.h"
#include "datastore.h"
#include "utilities.h"
#include "FFTCalculator.h"

#include "FFTWindow_cos2.h"
#include "lib/fftw++.h"

using namespace std;

struct FFT_threadInvoke{
	FFTCalculator* p;
	FFT_CalcParams params;
	
};

void FFT_Working_Thread( LPVOID pParam ){
	FFT_threadInvoke *ti=(FFT_threadInvoke* )pParam;
	 ti->p->DoCalc(ti->params);
}


FFTCalculator *FFTCalculator::instance = 0;
FFTCalculator::FFTCalculator(void)
{
	isOutputReady = false;
	source = DataStore::GetInstance();
}

FFTCalculator::~FFTCalculator(void)
{
	reset();
}

int FFTCalculator::EID2Index(int eid) const
{
	int ret=-1;
	for(size_t i=0;i<out.size();i++){
		if(out[i].eid==eid){
			ret=i;break;
		}
	}
	return ret;
}

bool FFTCalculator::StartCalc (const FFT_CalcParams p){
	//check params
	for(UINT i=0;i<p.channels_eid.size();i++)
	{
		const Channel *ch = source->GetChannelByEID(p.channels_eid[i] );
		if(ch ==NULL)
			return false;
		if( p.endpt>= ch->data.size() )
			return false;
	}
	isOutputReady = false;
	out.clear();

	FFT_threadInvoke ti;
	ti.p = this;
	ti.params = p;

	wbd.SetPrompt(_T("Calculating FFT"));
	_beginthread(FFT_Working_Thread, 0, (void *)&ti);
	wbd.DoModal();
	isOutputReady = true;
	return true;

}

void FFTCalculator::DoCalc(const FFT_CalcParams p){

	unsigned int S=p.endpt - p.startpt ;
	unsigned int np=S/2+1;//output size
	double *f=FFTWdouble(S);
	
	for(UINT i=0;i<p.channels_eid.size();i++){

		std::complex<double> *sout=FFTWComplex(np);
		if(!(f && sout))
			return;
		rcfft1d Forward(S,f,sout);
		//crfft1d Backward(n,g,f);
		FFTWindow *win = new FFTWindow_cos2(S,0.1,0.1);
		int n = source->GetElectrodeIndex(p.channels_eid[i]);

		for(UINT j=p.startpt ; j < p.endpt ; j++) {
			source->GetRefData(n,j,f[j-p.startpt]);
			//f[j-p.startpt]=win->Filter(f[j-p.startpt]);//too slow!!!
		}//copy
		delete win;
		Forward.fft(f,sout);

		//	FFT(in,out,r);
#ifdef _DEBUG1//this will slow down the program!
		std::ofstream ofs("fft.txt");

		/*for(int i=0;i<m;i++)
		ofs << out[i].real() <<"   " << out[i].imag() << endl;
		ofs<<endl<<endl;*/
		for(unsigned int j=0;j<np;j++)
			ofs<<std::abs(sout[j])<<std::endl;
		ofs.close();
#endif

		FFTOutput fo(n,p.channels_eid[i] ,sout,p.startpt,p.endpt);
		fo.abs=new double[np];
		double average=0.0;
		double max=std::abs(fo.out[1]);
		fo.max_index = 1;
		fo.abs[0]=std::abs(fo.out[0]);
		for(unsigned int j=1;j<np;j++){
			fo.abs[j]=std::abs(fo.out[j]);
			if(fo.abs[j]>max){
				max = fo.abs[j];
				fo.max_index = j;
			}
			average+=fo.abs[j];
		}
		fo.max=max;
		fo.average=average/np;
		out.push_back(fo);
		
	}
	FFTWdelete(f);
	//wbd.DestroyWindow();
	PostMessage(wbd.m_hWnd,WM_CLOSE,0,0);
}

bool FFTCalculator::Export2File(LPCTSTR filename, int eid) const
{
	wofstream ofs(filename);
	if(!ofs)
		return false;

	ofs<<L"Channel_eid,"<<eid<<endl;
	ofs<<L"Channel_name,"<<source->GetChannelByEID(eid)->electrode.name<<endl;
	ofs<<L"Electrode_id,"<<source->GetChannelByEID(eid)->electrodeID<<endl;
	ofs<<endl;

	int index = EID2Index(eid);

	ofs<<L"Points,"<<out[index].e-out[index].b<<endl;
	ofs<<L"Max.,"<<out[index].max<<endl;
	ofs<<L"Mean.,"<<out[index].average<<endl;
	ofs<<endl;
	ofs<<L"real,imag,module"<<endl;
	const int S=(out[index].e-out[index].b)/2+1;
	for(size_t i=0;i<S;i++)
		ofs<<out[index].out[i].real()<<L","<<out[index].out[i].imag()
		<<L","<<out[index].abs[i]<<endl;
	ofs.close();
	return true;
}
void FFTCalculator::reset(void)
{
	isOutputReady = false;
	//source = 0;
	for(size_t i = 0;i<out.size(); i++)
		KillAOutput(out[i]);
	out.clear();
	ATLTRACE(atlTraceUI,0, _T("Reset FFTC\n"));

}

void FFTCalculator::KillAOutput(FFTOutput &o){
	SAFE_DELETE(o.abs);
	FFTWdelete(o.out);
}
